import { modelOptions, pre, Prop, Severity, ReturnModelType } from "@typegoose/typegoose";
import { QueryOptions } from "mongoose";
import { COMMON_PROJECTION } from "../constants";
import { Is } from "../constants/enum";
import { HProjection, HSort, PagingInfo } from "../interface/common.interface";
import { serverMoment } from "../util/utilities";
@modelOptions({
  schemaOptions: {
    versionKey: false,
    timestamps: {
      createdAt: 'created_at',
      updatedAt: 'updated_at',
      currentTime: () => {
        return serverMoment().unix();
      }
    }
  },
  options: { allowMixed: Severity.ALLOW }
})
@pre<BaseEntity>(['save'], function() {
  this.updated_at = serverMoment().unix();
})
@pre<BaseEntity>(['remove'], function() {
  this.updated_at = serverMoment().unix();
  this.deleted_at = serverMoment().unix();
  this.is_deleted = Is.yes;
})
export default class BaseEntity {
  @Prop()
  created_at?: number;

  @Prop()
  created_by?: string;

  @Prop()
  updated_at?: number;

  @Prop()
  updated_by?: string;

  @Prop()
  deleted_at?: number;

  @Prop()
  deleted_by?: string;

  @Prop({ default: Is.no })
  is_deleted?: Is;

  public static async removeMany(this: ReturnModelType<typeof BaseEntity>, query: any) {
    await this.updateMany(query, { $set: { "deleted_at": serverMoment().unix(), "is_deleted": Is.yes }});
  }

  public static async removeOne(this: ReturnModelType<typeof BaseEntity>, query: any) {
    await this.updateOne(query, { $set: { "deleted_at": serverMoment().unix(), "is_deleted": Is.yes }});
  }

  public static async getCount(this: ReturnModelType<typeof BaseEntity>, query: any): Promise<number> {
    return await this.countDocuments(query).lean();
  }

  public static async findByPaging<T>(
    this: ReturnModelType<typeof BaseEntity>,
    query: any,
    paging: PagingInfo,
    sort?: HSort,
    projection?: HProjection,
    withDeleted?: Is
  ): Promise<T[]> {
    const condition = Object.assign({}, query);
    if (withDeleted !== Is.yes) {
      condition['is_deleted'] = Is.no;
    }
    const limit = paging.ps;
    const skip = (paging.pi - 1) * paging.ps + (paging.sp || 0);
    const queryOption: QueryOptions = { skip, limit };
    if (sort) {
      queryOption.sort = sort;
    }
    const finalProjection = Object.assign({}, COMMON_PROJECTION, projection);
    return await this.find(condition, finalProjection, queryOption).lean();
  }
}